/*
===========================================================================
This source file is part of DyLab (Dynamic Laboratory)
For the latest info, see http://dylab.googlecode.com

Copyright (c) 2006-2008 Lukas Krejci
(krejci.lukas@volny.cz)

This file is part of DyLab.

    DyLab is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    DyLab is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with DyLab.  If not, see <http://www.gnu.org/licenses/>.
===========================================================================
*/

#ifndef __dylab_AssocContainerBase_h__
#define __dylab_AssocContainerBase_h__

//===========================================================================================
#include <dylab/utils/containers/ContainerBase.h>
#include <dylab/utils/exceptions/EVerificationFailed.h>

//===========================================================================================
namespace dylab {

    /** 
     */   
    template <
        class _STLcontainerT
    >
    class AssocContainerBase 
        : public ContainerBase<_STLcontainerT>
    { 
    private:
        typedef typename _STLcontainerT::key_type KeyT;
        typedef typename _STLcontainerT::value_type::second_type MappedT;
    public:
        /// utility class (RIAA) for walking through all container elements
        class Iterator
            : public IteratorBase
        {
        public:
            Iterator(ContainerBaseT & _c)
                : IteratorBase(_c)
                    { }
            const KeyT & operator~ ()
                    { 
                        DYLAB_ASSERT(isValid());
                        return getCurrent()->first; 
                    }
            operator MappedT & ()
                    { 
                        DYLAB_ASSERT(isValid());
                        return getCurrent()->second; 
                    }
            MappedT & operator()()
                    { 
                        DYLAB_ASSERT(isValid());
                        return getCurrent()->second; 
                    }
            MappedT * operator-> ()
                    { 
                        DYLAB_ASSERT(isValid());
                        return &(getCurrent()->second); 
                    }
        };
        //-----------------------------------------------------------------------------
    public:
        /// utility class (RIAA) for walking through all container elements without the permission to modify them
        class ConstIterator
            : public ConstIteratorBase
        {
        public:
            ConstIterator(const ContainerBaseT & _c)
                : ConstIteratorBase(_c)
                    { }
            const KeyT & operator~ ()
                    { 
                        DYLAB_ASSERT(isValid());
                        return getCurrent()->first; 
                    }
            operator const MappedT & ()
                    { 
                        DYLAB_ASSERT(isValid());
                        return getCurrent()->second; 
                    }
            const MappedT & operator()()
                    { 
                        DYLAB_ASSERT(isValid());
                        return getCurrent()->second; 
                    }
            const MappedT * operator-> ()
                    { 
                        DYLAB_ASSERT(isValid());
                        return &(getCurrent()->second); 
                    }
        };
        //-----------------------------------------------------------------------------
    public:
        /// scoped reader class
        class Reader
            : public ReaderBase
        {
        public:
            Reader(const ContainerBaseT & _c)
                : ReaderBase(_c)
                    { }
            bool find(const KeyT & _key, MappedT * _valuePtr = NULL) const
                    {
                        _STLcontainerT::const_iterator it = mSTLcontainer->find(_key);
                        bool found = it != mSTLcontainer->end();
                        if (found && _valuePtr != NULL)
                            *_valuePtr = it->second;
                        return found;
                    }
            bool has(const KeyT & _key) const
                    { return mSTLcontainer->count(_key) > 0; }
            MappedT get(const KeyT & _key) const
                    { 
                        MappedT _value;
                        DYLAB_VERIFY(find(_key, &_value));
                        return _value;
                    }
        };
        //-----------------------------------------------------------------------------
    public:
        /// scoped writer class
        class Writer
            : public WriterBase
        {
        public:
            Writer(ContainerBaseT & _c)
                : WriterBase(_c)
                    { }
            void insert(const KeyT & _key, MappedT _value)
                    {
                        _STLcontainerT::iterator it = mSTLcontainer->find(_key);
                        DYLAB_ASSERT(it == mSTLcontainer->end());
                        mSTLcontainer->insert(_STLcontainerT::value_type(_key, _value));
                    }
            void remove(const KeyT & _key)
                    { 
                        _STLcontainerT::iterator it = mSTLcontainer->find(_key);
                        DYLAB_ASSERT(it != mSTLcontainer->end());
                        mSTLcontainer->erase(it);
                    }
            void removeAll()
                    { mSTLcontainer->clear(); }
        };
        //-----------------------------------------------------------------------------

    public:

        bool find(const KeyT & _key, MappedT * _valuePtr = NULL) const
                { return Reader(*this).find(_key, _valuePtr); }
        bool has(const KeyT & _key) const
                { return Reader(*this).has(_key); }
        MappedT get(const KeyT & _key) const
                { return Reader(*this).get(_key); }

        void insert(const KeyT & _key, MappedT _value)
                { Writer(*this).insert(_key, _value); }
        void remove(const KeyT & _key)
                { Writer(*this).remove(_key); }
        void removeAll()
                { Writer(*this).removeAll(); }
    };    

}
//===========================================================================================
#endif // __dylab_AssocContainerBase_h__
